/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
/**
 * 
 */
package com.genia.toolbox.mojo.gwt;

import org.apache.maven.plugin.logging.Log;

import com.google.gwt.core.ext.TreeLogger;

/**
 * a Gwt {@link TreeLogger} that allows to log back to the maven plugin.
 */
public class MavenLogger
    extends TreeLogger
{

  /**
   * line to describe the category.
   */
  private String headLine;

  /**
   * the {@link Log} to log to.
   */
  private Log log;

  /**
   * the level of the logger.
   */
  private int level;



  /**
   * constructor.
   * 
   * @param log
   *          the {@link Log} to log to
   */
  public MavenLogger(Log log)
  {
    this(log, 0, null);
  }



  /**
   * constructor.
   * 
   * @param log
   *          the {@link Log} to log to
   * @param level
   *          the level of the logger
   * @param headline
   *          line to describe the category
   */
  public MavenLogger(Log log, int level, String headline)
  {
    this.log = log;
    this.level = level;
    this.headLine = headline;
  }



  /**
   * Determines whether or not a log entry of the specified type would actually
   * be logged. Caller use this method to avoid constructing log messages that
   * would be thrown away.
   * 
   * @param type
   *          the {@link Type} to examine
   * @return <code>true</code> if the given {@link Type} must produce logs.
   * @see TreeLogger#isLoggable(com.google.gwt.core.ext.TreeLogger.Type)
   */
  @Override
  public boolean isLoggable(Type type)
  {
    if (type == Type.DEBUG) {
      return log.isDebugEnabled();
    }
    if (type == Type.INFO) {
      return log.isInfoEnabled();
    }
    if (type == Type.WARN) {
      return log.isWarnEnabled();
    }
    if (type == Type.ERROR) {
      return log.isErrorEnabled();
    }
    return false;
  }



  /**
   * returns the prefix to display for the current logger.
   * 
   * @return the prefix to display for the current logger
   */
  private String getPrefix()
  {
    return getPrefix(level);
  }



  /**
   * returns the prefix to display for the given level.
   * 
   * @param level
   *          the level to get the prefix for
   * @return the prefix to display for the given level
   */
  private String getPrefix(int level)
  {
    if (level <= 0) {
      return "";
    }
    return " " + getPrefix(level - 1);
  }



  /**
   * returns the message to log.
   * 
   * @param msg
   *          An optional message to log, which can be <code>null</code> if
   *          only an exception is being logged
   * @param caught
   *          An optional exception to log, which can be <code>null</code> if
   *          only a message is being logged
   * @return the message to log
   */
  private String getMessageToLog(String msg, Throwable caught)
  {
    String res = "";
    if (headLine != null) {
      res = headLine;
    }
    if (msg != null) {
      headLine = null;
      return res + getPrefix() + msg;
    }
    if (caught != null) {
      headLine = null;
      return res + getPrefix() + caught.getMessage();
    }
    return null;
  }



  /**
   * Produces a branched logger, which can be used to write messages that are
   * logically grouped together underneath the current logger. The details of
   * how/if the resulting messages are displayed is implementation-dependent.
   * <p>
   * The log message supplied when branching serves two purposes. First, the
   * message should be considered a heading for all the child messages below it.
   * Second, the <code>type</code> of the message provides a hint as to the
   * importance of the children below it. As an optimization, an implementation
   * could return a "no-op" logger if messages of the specified type weren't
   * being logged, which the implication being that all nested log messages were
   * no more important than the level of their branch parent.
   * </p>
   * <p>
   * As an example of how hierarchical logging can be used, a branched logger in
   * a GUI could write log message as child items of a parent node in a tree
   * control. If logging to streams, such as a text console, the branched logger
   * could prefix each entry with a unique string and indent its text so that it
   * could be sorted later to reconstruct a proper hierarchy.
   * </p>
   * 
   * @param type
   *          the level of the log
   * @param msg
   *          an optional message to log, which can be <code>null</code> if
   *          only an exception is being logged
   * @param caught
   *          an optional exception to log, which can be <code>null</code> if
   *          only a message is being logged
   * @param helpInfo
   *          extra information that might be used by the logger to provide
   *          extended information to the user
   * @return an instance of {@link TreeLogger} representing the new branch of
   *         the log; may be the same instance on which this method is called
   * @see com.google.gwt.core.ext.TreeLogger#branch(com.google.gwt.core.ext.TreeLogger.Type,
   *      java.lang.String, java.lang.Throwable,
   *      com.google.gwt.core.ext.TreeLogger.HelpInfo)
   */
  @Override
  public TreeLogger branch(Type type, String msg, Throwable caught, HelpInfo helpInfo)
  {
    return new MavenLogger(log, level + 1, getMessageToLog(msg, caught));
  }



  /**
   * Logs a message and/or an exception, with optional help info. It is also
   * legal to call this method using <code>null</code> arguments for <i>both</i>
   * <code>msg</code> and <code>caught</code>, in which case the log event
   * can be ignored. The <code>info</code> can provide extra information to
   * the logger; a logger may choose to ignore this info.
   * 
   * @param type
   *          the level of the log
   * @param msg
   *          an optional message to log, which can be <code>null</code> if
   *          only an exception is being logged
   * @param caught
   *          an optional exception to log, which can be <code>null</code> if
   *          only a message is being logged
   * @param helpInfo
   *          extra information that might be used by the logger to provide
   *          extended information to the user
   * @see com.google.gwt.core.ext.TreeLogger#log(com.google.gwt.core.ext.TreeLogger.Type,
   *      java.lang.String, java.lang.Throwable,
   *      com.google.gwt.core.ext.TreeLogger.HelpInfo)
   */
  @Override
  public void log(Type type, String msg, Throwable caught, HelpInfo helpInfo)
  {
    if (type == Type.DEBUG && log.isDebugEnabled()) {
      log.debug(getMessageToLog(msg, caught));
    }
    if (type == Type.INFO && log.isInfoEnabled()) {
      log.info(getMessageToLog(msg, caught));
    }
    if (type == Type.WARN && log.isWarnEnabled()) {
      log.warn(getMessageToLog(msg, caught));
    }
    if (type == Type.ERROR && log.isErrorEnabled()) {
      log.error(getMessageToLog(msg, caught));
    }
  }
}
